博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件
阅读量:7181 次
发布时间:2019-06-29

本文共 40198 字,大约阅读时间需要 133 分钟。

上一篇文章介绍到怎么在自己的Java环境中搭建openfire插件开发的环境,同时介绍到怎样一步步简单的开发openfire插件。一步步很详细的介绍到简单插件开发,带Servlet的插件的开发、带JSP页面插件的开发,以及怎么样将开发好的插件打包、部署到openfire服务器。

 

如果你没有看上一篇文章的话,请你还是看看。

因为这篇文章是基于上篇文章讲叙的基础上完成插件开发。而且开发的环境及打包的ant脚本都是共用的。如果你在看这篇文章有什么不好理解的地方,还请麻烦你自己再去翻阅之前的文章。这样对你可能有更多的帮助!

 

同样在这篇文章开始之前,如果你不知道怎么使用openfire,安装openfire服务器,建议你看以下文章:

 

开发环境:

System:Windows

WebBrowser:IE6+、Firefox3+

JavaEE Server:tomcat5.0.2.8、tomcat6

IDE:eclipse、MyEclipse 6.5

开发依赖库:

Jdk1.6、jasper-compiler.jar、jasper-runtime.jar、openfire.jar、servlet.jar

Email:hoojo_@126.com

Blog:

如果你觉得这篇文章不错或对你有帮助的话,请你支持我。如果觉这里的文章不错的话,请你关注我的博客。

 

推荐文章:

【】 手把手教你配置Openfire服务器

【】教你一步步开发自己的插件

【】 优美清新的界面,可以多窗口聊天

【】 可以基于他开发Java的聊天应用

【】 多人聊天室,如果结合Smack和Openfire,就可以实现外网聊天应用

【】 本地应用,不需要Openfire服务器

【】理论知识,便于连接Openfire

【】 拓展你的应用,可以了解开源的jwchat,全JS的应用

【】 移动手机和Openfire的整合方案

【】 DWR实现聊天应用,简单快速

 

我把自己写好的插件打包,下载后部署到openfire服务器,就可以用了。如果出现什么问题的话,你可以看看这篇文章,都有解决方法。

插件下载:

 

基本原理(流程)

 

一、准备工作

1、 这里的开发环境就是的开发环境,如果你还没有配置好环境或不知道怎么样配置。那么烦请你按照上一篇博文的讲述方法配置好开发环境,然后跟着我一步步开发聊天记录插件。

2、 基于之前讲的,现在在环境中创建好插件的目录结构。新建一个plugins/chatlogs目录,新插件的目录文件如下,里面的部分文件是通用的,只有在src/plugins/chatlogs目录中文件才是这次新增的文件。这次的插件目录结构会按照下面的结构来。

先熟悉下上面的目录,就简单大致介绍下上面的目录。在src/plugins/chatlogs目录中的包是主要开发的插件核心代码。

其中ChatLogsPlugin.java是聊天记录拦截聊天记录,并保存到数据库中的重要代码。

ChatLogsServlet.java是对外公开访问的Servlet,它会返回一些xml的内容,主要是聊天记录的内容和聊天用户的等XML格式的数据。

DbChatLogsManager.java这个也是很主要的,它主要完成对聊天记录数据库表的CRUD操作。

database目录中存放的是sql脚本,这里我提供的是oracle和hsql两个数据库的脚步。至于使用说明脚步要看你的openfire服务器使用的数据库才行。

web目录上次介绍到了,主要是jsp页面。

同时在src/plugins/chatlogs目录中还存在一些gif和html,这些都是插件的介绍和安装内容、图标等。

plugin.xml是插件核心代码的配置和jsp页面的配置文件。

其他内容之前介绍过了,这里就不再一一赘述。

 

3、 执行你的聊天记录数据库脚本,聊天记录表内容如下

hsql db

-- Create table --openfire聊天记录
createtable OFCHATLOGS
(
MESSAGEID  int primary key,    --消息id
SESSIONJID VARCHAR(30),        --用户session jid名称
SENDER    VARCHAR(30),         --消息发送者
RECEIVER     VARCHAR(30),        --接受者
CREATEDATE VARCHAR(30),        --消息发送、创建时间
LENGTH    int,                 --消息长度、大小
CONTENT    VARCHAR(2000),        --消息内容
DETAIL     VARCHAR(4000),        --消息源报文
STATE         int                --删除状态,1表示删除
);

 

Oracle db

-- Create table
createtable OFCHATLOGS
(
MESSAGEID  int not null,
SESSIONJID NVARCHAR2(30),
SENDER     NVARCHAR2(30),
RECEIVER      NVARCHAR2(30),
CREATEDATE NVARCHAR2(30),--TIMESTAMP(12),
LENGTH     int,
CONTENT    NVARCHAR2(2000),
DETAIL     NVARCHAR2(4000),
STATE         int
);
-- Add comments to the table
comment on table OFCHATLOGS
is'openfire聊天记录';
-- Add comments to the columns
comment on column OFCHATLOGS.MESSAGEID
is'消息id';
comment on column OFCHATLOGS.SESSIONJID
is'用户session jid名称';
comment on column OFCHATLOGS.SENDER
is'消息发送者';
comment on column OFCHATLOGS.RECEIVER
is'接受者';
comment on column OFCHATLOGS.CREATEDATE
is'消息发送、创建时间';
comment on column OFCHATLOGS.LENGTH
is'消息长度、大小';
comment on column OFCHATLOGS.CONTENT
is'消息内容';
comment on column OFCHATLOGS.DETAIL
is'消息源报文';
comment on column OFCHATLOGS.STATE
is'删除状态,1表示删除';
-- Create/Recreate primary, unique and foreign key constraints
Alter table OFCHATLOGS
Add constraint PKMESSAGEID primary key (MESSAGEID);

注意:如果你是oracle数据库,执行上面的脚本可能没有什么问题。如果你是使用openfire默认的数据库hsql db。那么你可能不知道在哪里运行hql 脚本。不要急,跟着我做!这些都是小菜一碟的事情。

下面的内容是openfire默认数据库的脚本和数据库的使用方法,不是用openfire默认数据库的“攻城师”可以跳过。

 

3.1 进入到你的openfire安装目录C:\Program Files\openfire\bin\extra,在该目录下你可以看到

这个就是数据库启动的dos程序,如果你是Linux的系统。那当然是运行embedded-db-viewer.sh这个。如果你的windows的系统,就运行embedded-db-viewer.bat程序。

注意:在启动数据库前,请保证你的openfire服务器没有启动。要不然你是无法启动的。因为你启动了openfire服务器的话,数据库已经在使用了,Openfire会锁定数据库的。因为openfire不希望在读写数据的时候,有人在干预它,导致存在脏读,重写的情况。

 

3.2 启动后就可以看到如下界面

在空白区域你可以写你的SQL脚本,写完后点击Excute SQL 就可以运行。执行完成后,在右下方区域可以看到结果。

Ok,你现在就可以将hsql的聊天记录表的脚本放在这里执行。数据库表就可以创建成功了。创建成功后你可以看到下面输出update count 0。在左边可以看到OFCHATLOGS这个table。

创建好数据库表后,下面我们就开发自己的openfire聊天插件核心代码。

 

4、 在开始核心代码之前,我们需要建立一个简单的JavaEntity实体对象。在src/plugins/chatlogs目录中建立com.hoo.openfire.chat.logs.entity包,在包下建立文件

package com.hoo.openfire.chat.logs.entity;
 
import java.sql.Timestamp;
import org.jivesoftware.util.JiveConstants;
 
/**
* function: 聊天记录对象实体
* @author hoojo
* @createDate 2012-9-19 下午08:28:03
* @file ChatLogs.java
* @package com.hoo.openfire.chat.logs.entity
* @project OpenfirePlugin
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class ChatLogs {
 
private long messageId;
private String sessionJID;
private String sender;
private String receiver;
private Timestamp createDate;
private String content;
private String detail;
private int length;
private int state; // 1 表示删除
 
public interface LogState {
int show = 0;
int remove = 1;
}
 
/**
* function: 自增id序列管理器,类型变量
* @author hoojo
* @createDate 2012-9-20 下午02:38:52
* @file ChatLogs.java
* @package com.hoo.openfire.chat.logs.entity
* @project OpenfirePlugin
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class ChatLogsConstants extends JiveConstants {
// 日志表id自增对应类型
public static final int CHAT_LOGS = 52;
// 用户在线统计id自增对应类型
public static final int USER_ONLINE_STATE = 53;
}
 
public ChatLogs() {
}
 
public ChatLogs(String sessionJID, Timestamp createDate, String content, String detail, int length) {
super();
this.sessionJID = sessionJID;
this.createDate = createDate;
this.content = content;
this.detail = detail;
this.length = length;
}
 
public ChatLogs(long messageId, String sessionJID, Timestamp createDate, String content, String detail, int length, int state) {
super();
this.messageId = messageId;
this.sessionJID = sessionJID;
this.createDate = createDate;
this.content = content;
this.detail = detail;
this.length = length;
this.state = state;
}
 
// setter/getter
}

二、开发聊天记录插件

按照上面给出的工程的目录结构,新建我们需要的文件。

1、 在src/plugins/chatlogs目录新建包com.hoo.openfire.chat.logs,在包中建立DbChatLogsManager 聊天记录CRUD数据库操作类

package com.hoo.openfire.chat.logs;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.jivesoftware.database.DbConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import com.hoo.openfire.chat.logs.entity.ChatLogs;
 
/**
* function: 聊天记录db操作类
* @author hoojo
* @createDate 2012-9-19 下午04:15:43
* @file DbChatLogsManager.java
* @package com.iflashbuy.openfire.chat.logs
* @project OpenfirePlugin
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class DbChatLogsManager {
 
private static final Logger Log = LoggerFactory.getLogger(DbChatLogsManager.class);
private static final DbChatLogsManager CHAT_LOGS_MANAGER = new DbChatLogsManager();
 
private DbChatLogsManager() {
}
 
public static DbChatLogsManager getInstance() {
return CHAT_LOGS_MANAGER;
}
 
private static final String LOGS_COUNT = "SELECT count(1) FROM ofChatLogs";
private static final String LOGS_LAST_MESSAGE_ID = "SELECT max(messageId) FROM ofChatLogs";
private static final String LOGS_FIND_BY_ID = "SELECT messageId, sessionJID, sender, receiver, createDate, length, content FROM ofChatLogs where messageId = ?";
private static final String LOGS_REMOVE = "UPDATE ofChatLogs set state = 1 where messageId = ?";//"DELETE FROM ofChatLogs WHERE messageId = ?";
private static final String LOGS_INSERT = "INSERT INTO ofChatLogs(messageId, sessionJID, sender, receiver, createDate, length, content, detail, state) VALUES(?,?,?,?,?,?,?,?,?)";
private static final String LOGS_QUERY = "SELECT messageId, sessionJID, sender, receiver, createDate, length, content FROM ofChatLogs where state = 0";
private static final String LOGS_SEARCH = "SELECT * FROM ofChatLogs where state = 0";
private static final String LOGS_LAST_CONTACT = "SELECT distinct receiver FROM ofChatLogs where state = 0 and sender = ?";
private static final String LOGS_ALL_CONTACT = "SELECT distinct sessionJID FROM ofChatLogs where state = 0";
 
/**
* function: 获取最后一个id
* @author hoojo
* @createDate 2012-9-19 下午08:13:33
* @return 最后一个记录id
*/
public int getLastId() {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
int count = -1;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOGS_LAST_MESSAGE_ID);
rs = pstmt.executeQuery();
if (rs.next()) {
count = rs.getInt(1);
} else {
count = 0;
}
} catch (SQLException sqle) {
Log.error(sqle.getMessage(), sqle);
return 0;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
return count;
}
 
/**
* function: 获取总数量
* @author hoojo
* @createDate 2012-9-19 下午08:14:59
* @return 总数量
*/
public int getCount() {
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
int count = -1;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOGS_COUNT);
rs = pstmt.executeQuery();
if (rs.next()) {
count = rs.getInt(1);
} else {
count = 0;
}
} catch (SQLException sqle) {
Log.error(sqle.getMessage(), sqle);
return 0;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
return count;
}
 
/**
* function: 删除聊天记录信息
* @author hoojo
* @createDate 2012-9-19 下午08:25:48
* @param id 聊天信息id
* @return
*/
public boolean remove(Integer id) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOGS_REMOVE);
pstmt.setInt(1, id);
return pstmt.execute();
 
} catch (SQLException sqle) {
Log.error("chatLogs remove exception: {}", sqle);
return false;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
 
/**
* function: 添加聊天记录信息
* @author hoojo
* @createDate 2012-9-19 下午08:37:52
* @param logs ChatLogs 聊天记录对象
* @return 是否添加成功
*/
public boolean add(ChatLogs logs) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOGS_INSERT);
int i = 1;
pstmt.setLong(i++, logs.getMessageId());
pstmt.setString(i++, logs.getSessionJID());
pstmt.setString(i++, logs.getSender());
pstmt.setString(i++, logs.getReceiver());
pstmt.setTimestamp(i++, logs.getCreateDate());
pstmt.setInt(i++, logs.getLength());
pstmt.setString(i++, logs.getContent());
pstmt.setString(i++, logs.getDetail());
pstmt.setInt(i++, logs.getState());
 
return pstmt.execute();
} catch (SQLException sqle) {
Log.error("chatLogs add exception: {}", sqle);
return false;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
 
/**
* function: 通过id查询聊天记录信息
* @author hoojo
* @createDate 2012-9-19 下午09:32:19
* @param id 消息id
* @return ChatLogs
*/
public ChatLogs find(int id) {
Connection con = null;
PreparedStatement pstmt = null;
ChatLogs logs = null;
 
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOGS_FIND_BY_ID);
pstmt.setInt(1, id);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
logs = new ChatLogs();
logs.setMessageId(rs.getInt("messageId"));
logs.setContent(rs.getString("content"));
logs.setCreateDate(rs.getTimestamp("createDate"));
logs.setLength(rs.getInt("length"));
logs.setSessionJID(rs.getString("sessionJID"));
logs.setSender(rs.getString("sender"));
logs.setReceiver(rs.getString("receiver"));
}
return logs;
} catch (SQLException sqle) {
Log.error("chatLogs find exception: {}", sqle);
return logs;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
 
/**
* function: 多条件搜索查询,返回List<ChatLogs>集合
* @author hoojo
* @createDate 2012-9-19 下午09:34:45
* @param entity ChatLogs
* @return 返回List<ChatLogs>集合
*/
public List
query(ChatLogs entity) {
Connection con = null;
Statement pstmt = null;
ChatLogs logs = null;
 
List
result = new ArrayList
();
 
try {
con = DbConnectionManager.getConnection();
pstmt = con.createStatement();
 
String sql = LOGS_QUERY;
if (entity != null) {
if (!StringUtils.isEmpty(entity.getSender()) && !StringUtils.isEmpty(entity.getReceiver())) {
sql += " and (sender = '" + entity.getSender() + "' and receiver = '" + entity.getReceiver() + "')";
sql += " or (receiver = '" + entity.getSender() + "' and sender = '" + entity.getReceiver() + "')";
 
} else {
if (!StringUtils.isEmpty(entity.getSender())) {
sql += " and sender = '" + entity.getSender() + "'";
}
if (!StringUtils.isEmpty(entity.getReceiver())) {
sql += " and receiver = '" + entity.getReceiver() + "'";
}
}
 
 
if (!StringUtils.isEmpty(entity.getContent())) {
sql += " and content like '%" + entity.getContent() + "%'";
}
if (entity.getCreateDate() != null) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String crateatDate = df.format(new Date(entity.getCreateDate().getTime()));
//sql += " and to_char(createDate, 'yyyy-mm-dd') = '" + crateatDate + "'";
sql += " and createDate like '" + crateatDate + "%'";
}
}
sql += " order by createDate asc";
ResultSet rs = pstmt.executeQuery(sql);
while (rs.next()) {
logs = new ChatLogs();
logs.setMessageId(rs.getInt("messageId"));
logs.setContent(rs.getString("content"));
logs.setCreateDate(rs.getTimestamp("createDate"));
logs.setLength(rs.getInt("length"));
logs.setSessionJID(rs.getString("sessionJID"));
logs.setSender(rs.getString("sender"));
logs.setReceiver(rs.getString("receiver"));
result.add(logs);
}
return result;
} catch (SQLException sqle) {
Log.error("chatLogs search exception: {}", sqle);
return result;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
 
/**
* function: 多条件搜索查询,返回List集合
* @author hoojo
* @createDate 2012-9-19 下午09:33:28
* @param entity ChatLogs
* @return List
>
*/
public List
> search(ChatLogs entity) {
Connection con = null;
Statement pstmt = null;
 
List
> result = new ArrayList
>();
 
try {
con = DbConnectionManager.getConnection();
pstmt = con.createStatement();
 
String sql = LOGS_SEARCH;
if (entity != null) {
if (!StringUtils.isEmpty(entity.getSender()) && !StringUtils.isEmpty(entity.getReceiver())) {
sql += " and (sender = '" + entity.getSender() + "' and receiver = '" + entity.getReceiver() + "')";
sql += " or (receiver = '" + entity.getSender() + "' and sender = '" + entity.getReceiver() + "')";
 
} else {
if (!StringUtils.isEmpty(entity.getSender())) {
sql += " and sender = '" + entity.getSender() + "'";
}
if (!StringUtils.isEmpty(entity.getReceiver())) {
sql += " and receiver = '" + entity.getReceiver() + "'";
}
}
if (!StringUtils.isEmpty(entity.getContent())) {
sql += " and content like '%" + entity.getContent() + "%'";
}
if (entity.getCreateDate() != null) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String crateatDate = df.format(new Date(entity.getCreateDate().getTime()));
sql += " and to_char(createDate, 'yyyy-mm-dd') = '" + crateatDate + "'";
}
}
sql += " order by createDate asc";
ResultSet rs = pstmt.executeQuery(sql);
 
ResultSetMetaData rsmd = rs.getMetaData();
/** 获取结果集的列数*/
int columnCount = rsmd.getColumnCount();
while (rs.next()) {
HashMap
map = new HashMap
();
/** 把每一行以(key, value)存入HashMap, 列名做为key,列值做为value */
for (int i = 1; i <= columnCount; ++i) {
String columnVal = rs.getString(i);
if (columnVal == null) {
columnVal = "";
}
map.put(rsmd.getColumnName(i), columnVal);
}
/** 把装有一行数据的HashMap存入list */
result.add(map);
}
return result;
} catch (SQLException sqle) {
Log.error("chatLogs search exception: {}", sqle);
return result;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
 
/**
* function: 最近联系人
* @author hoojo
* @createDate 2013-3-24 下午4:38:51
* @param entity 聊天记录实体
* @return 最近联系人集合
*/
public List
findLastContact(ChatLogs entity) {
Connection con = null;
PreparedStatement pstmt = null;
List
result = new ArrayList
();
 
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOGS_LAST_CONTACT);
pstmt.setString(1, entity.getSender());
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
result.add(rs.getString("receiver"));
}
return result;
} catch (SQLException sqle) {
Log.error("chatLogs find exception: {}", sqle);
return result;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
 
/**
* function: 查找所有聊天用户
* @author hoojo
* @createDate 2013-3-24 下午4:37:40
* @return 所有聊天用户sessionJID集合
*/
public List
findAllContact() {
Connection con = null;
PreparedStatement pstmt = null;
List
result = new ArrayList
();
 
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOGS_ALL_CONTACT);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
result.add(rs.getString("sessionJID"));
}
return result;
} catch (SQLException sqle) {
Log.error("chatLogs find exception: {}", sqle);
return result;
} finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
}

比较简单,都是数据库的增删改查的JDBC操作。就是打开数据库连接和关闭数据库连接是使用openfire提供的DbConnectionManager类完成的。

 

2、 插件核心类,也就是保存聊天记录的类。这里对PacketInterceptor、Plugin进行继承。如果开发插件就一定要继承Plugin,而继承PacketInterceptor是拦截用户发送的消息包。对消息包进行过滤、拦截,保存我们需要的数据。openfire 的插件可以访问所有openfire的API。这给我们的插件实现提供了巨大的灵活性。以下提供了四种比较常用的插件集成方式。

2.1、Component:可以接收一个特定子域(sub-domain)的所有包。比如test_componet.hoo.com。所以一个发送给jojo@test_componet.hoo.com的包将被转发给这个componet.

2.2、IQHandler:相应包中特定的元素名或命名空间。下面的代码展示了如何注册一个IQHandler.

IQHandler myHandler = new MyIQHander();

IQRouter iqRouter = XMPPServer.getInstance().getIQRouter();

iqRouter.addHandler(myHandler);

2.3、PacketInterceptor:这种方式可以接收系统传输的所有包,并可以随意的丢弃它们。例如,一个interceptor 可以拦截并丢弃所有含有不健康信息的消息,或者将它们报告给系统管理员。

2.4、使用JiveGlobals.getProperty(String) 和 JiveGlobals.setProperty(String, String) 方法将我们的插件设置为openfire的一个全局属性。通过实现org.jivesoftware.util.PropertyEventListener方法可以将我们的插件做成一个属性监听器监听任何属性的变化。通过 PropertyEventDispatcher.addListener(PropertyEventListener)方法可以注册监听。要注意的一点是,一定要在destroyPlugin()方法中将注册的监听注销。

在src/plugins/chatlogs目录下新建ChatLogsPlugin类,插件核心类代码如下

package com.hoo.openfire.chat.logs;
 
import java.io.File;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.user.UserManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
import com.hoo.openfire.chat.logs.entity.ChatLogs;
import com.hoo.openfire.chat.logs.entity.ChatLogs.ChatLogsConstants;
 
/**
* function: 聊天记录插件
* @author hoojo
* @createDate 2012-9-19 下午01:47:20
* @file ChatLogsPacketInterceptor.java
* @package com.hoo.openfire.chat.logs
* @project OpenfirePlugin
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class ChatLogsPlugin implements PacketInterceptor, Plugin {
 
private static final Logger log = LoggerFactory.getLogger(ChatLogsPlugin.class);
 
private static PluginManager pluginManager;
private static DbChatLogsManager logsManager;
 
public ChatLogsPlugin() {
interceptorManager = InterceptorManager.getInstance();
logsManager = DbChatLogsManager.getInstance();
}
 
//Hook for intercpetorn
private InterceptorManager interceptorManager;
 
/**
* function: 拦截消息核心方法,Packet就是拦截消息对象
* @author hoojo
* @createDate 2013-3-27 下午04:49:11
*/
@Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed) throws PacketRejectedException {
if (session != null) {
debug(packet, incoming, processed, session);
}
 
JID recipient = packet.getTo();
if (recipient != null) {
String username = recipient.getNode();
// 广播消息或是不存在/没注册的用户.
if (username == null || !UserManager.getInstance().isRegisteredUser(recipient)) {
return;
} else if (!XMPPServer.getInstance().getServerInfo().getXMPPDomain().equals(recipient.getDomain())) {
// 非当前openfire服务器信息
return;
} else if ("".equals(recipient.getResource())) {
}
}
this.doAction(packet, incoming, processed, session);
}
 
/**
* function: 执行保存/分析聊天记录动作
* @author hoojo
* @createDate 2013-3-24 下午12:20:56
* @param packet 数据包
* @param incoming true表示发送方
* @param session 当前用户session
*/
private void doAction(Packet packet, boolean incoming, boolean processed, Session session) {
Packet copyPacket = packet.createCopy();
if (packet instanceof Message) {
Message message = (Message) copyPacket;
 
// 一对一聊天,单人模式
if (message.getType() == Message.Type.chat) {
log.info("单人聊天信息:{}", message.toXML());
debug("单人聊天信息:" + message.toXML());
 
// 程序执行中;是否为结束或返回状态(是否是当前session用户发送消息)
if (processed || !incoming) {
return;
}
logsManager.add(this.get(packet, incoming, session));
 
// 群聊天,多人模式
} else if (message.getType() ==  Message.Type.groupchat) {
List
els = message.getElement().elements("x");
if (els != null && !els.isEmpty()) {
log.info("群聊天信息:{}", message.toXML());
debug("群聊天信息:" + message.toXML());
} else {
log.info("群系统信息:{}", message.toXML());
debug("群系统信息:" + message.toXML());
}
 
// 其他信息
} else {
log.info("其他信息:{}", message.toXML());
debug("其他信息:" + message.toXML());
}
} else if (packet instanceof IQ) {
IQ iq = (IQ) copyPacket;
if (iq.getType() == IQ.Type.set && iq.getChildElement() != null && "session".equals(iq.getChildElement().getName())) {
log.info("用户登录成功:{}", iq.toXML());
debug("用户登录成功:" + iq.toXML());
}
} else if (packet instanceof Presence) {
Presence presence = (Presence) copyPacket;
if (presence.getType() == Presence.Type.unavailable) {
log.info("用户退出服务器成功:{}", presence.toXML());
debug("用户退出服务器成功:" + presence.toXML());
}
}
}
 
/**
* function: 创建一个聊天记录实体对象,并设置相关数据
* @author hoojo
* @createDate 2013-3-27 下午04:44:54
* @param packet 数据包
* @param incoming 如果为ture就表明是发送者
* @param session 当前用户session
* @return 聊天实体
*/
private ChatLogs get(Packet packet, boolean incoming, Session session) {
Message message = (Message) packet;
ChatLogs logs = new ChatLogs();
 
JID jid = session.getAddress();
if (incoming) {        // 发送者
logs.setSender(jid.getNode());
JID recipient = message.getTo();
logs.setReceiver(recipient.getNode());
}
logs.setContent(message.getBody());
logs.setCreateDate(new Timestamp(new Date().getTime()));
logs.setDetail(message.toXML());
logs.setLength(logs.getContent().length());
logs.setState(0);
logs.setSessionJID(jid.toString());
// 生成主键id,利用序列生成器
long messageID = SequenceManager.nextID(ChatLogsConstants.CHAT_LOGS);
logs.setMessageId(messageID);
 
return logs;
}
 
/**
* function: 调试信息
* @author hoojo
* @createDate 2013-3-27 下午04:44:31
* @param packet 数据包
* @param incoming 如果为ture就表明是发送者
* @param processed 执行
* @param session 当前用户session
*/
private void debug(Packet packet, boolean incoming, boolean processed, Session session) {
String info = "[ packetID: " + packet.getID() + ", to: " + packet.getTo() + ", from: " + packet.getFrom() + ", incoming: " + incoming + ", processed: " + processed + " ]";
 
long timed = System.currentTimeMillis();
debug("################### start ###################" + timed);
debug("id:" + session.getStreamID() + ", address: " + session.getAddress());
debug("info: " + info);
debug("xml: " + packet.toXML());
debug("################### end #####################" + timed);
 
log.info("id:" + session.getStreamID() + ", address: " + session.getAddress());
log.info("info: {}", info);
log.info("plugin Name: " + pluginManager.getName(this) + ", xml: " + packet.toXML());
}
 
private void debug(Object message) {
if (true) {
System.out.println(message);
}
}
 
@Override
public void destroyPlugin() {
interceptorManager.removeInterceptor(this);
debug("销毁聊天记录插件成功!");
}
 
@Override
public void initializePlugin(PluginManager manager, File pluginDirectory) {
interceptorManager.addInterceptor(this);
pluginManager = manager;
 
debug("安装聊天记录插件成功!");
}
}

注意在初始化插件的时候,在系统的烂机器管理器中添加对当前插件对象的管理,即在interceptorManager中addInterceptor。而在销毁资源的时候则removeInterceptor当前对象。

上面已经在打印出用户聊天的Packet信息,当用户登陆、退出、发送消息等,都会被拦截到。我们只需要拦截我们要的消息数据,注意下面看这段代码

// 程序执行中;是否为结束或返回状态(是否是当前session用户发送消息)
if (processed || !incoming) {
return;
}

如果没有这段代码,那我们就可以保存很多重复或无用的信息。为什么这样写,看看在控制台或日子info中的信息:

一个用户hoojo和离线用户boy聊天Packet内容

################### start ###################1364442703632
id:172af964, address: hoojo@127.0.0.1/Spark 2.6.3
info: [ packetID: 4O1WO-29, to: boy@127.0.0.1, from: hoojo@127.0.0.1/Spark 2.6.3, incoming: true, processed: false ]
xml: 
哈哈,我上线了~~
yOgoRq
################### end #####################1364442703632
 
################### start ###################1364442703659
id:172af964, address: hoojo@127.0.0.1/Spark 2.6.3
info: [ packetID: 4O1WO-29, to: boy@127.0.0.1, from: hoojo@127.0.0.1/Spark 2.6.3, incoming: true, processed: true ]
xml: 
哈哈,我上线了~~
yOgoRq
################### end #####################1364442703659

主要看incoming和processed的值:incoming都为ture,incoming为true就表示是自己发送的信息。而procesed为false,然后才是true,processed为true就表示发送结束。且session都是当前聊天用户。

 incoming:true,processed:false;

-->  incoming:true,processed:true;

通过这个状态,我们的判断代码应该可以拦截到的是 第一种状态。然后就可以将一种状态的Packet保存到聊天记录表中,其他的数据暂不处理!

用户hoojo和一个在线用户boy聊天Packet

################### start ###################1364443976157
id:172af964, address: hoojo@127.0.0.1/Spark 2.6.3
info: [ packetID: 4O1WO-30, to: boy@127.0.0.1, from: hoojo@127.0.0.1/Spark 2.6.3, incoming: true, processed: false ]
xml: 
看状态……
yOgoRq
################### end #####################1364443976157
################### start ###################1364443976223
id:1f30f584, address: boy@127.0.0.1/WebIM
info: [ packetID: 4O1WO-30, to: boy@127.0.0.1, from: hoojo@127.0.0.1/Spark 2.6.3, incoming: false, processed: false ]
xml: 
看状态……
yOgoRq
################### end #####################1364443976223
################### start ###################1364443976228
id:1f30f584, address: boy@127.0.0.1/WebIM
info: [ packetID: 4O1WO-30, to: boy@127.0.0.1, from: hoojo@127.0.0.1/Spark 2.6.3, incoming: false, processed: true ]
xml: 
看状态……
yOgoRq
################### end #####################1364443976228
################### start ###################1364443976232
id:172af964, address: hoojo@127.0.0.1/Spark 2.6.3
info: [ packetID: 4O1WO-30, to: boy@127.0.0.1, from: hoojo@127.0.0.1/Spark 2.6.3, incoming: true, processed: true ]
xml: 
看状态……
yOgoRq
################### end #####################1364443976232

 

状态流程:

 incoming:true,processed:false;

-->  incoming:false,processed:false;

-->  incoming:false,processed:true;

--> incoming:true,processed:true;

而我们保存消息的状态是在第一个状态,即incoming=true,processed=false的这个状态保存的。

 

看图,这样更利于理解

离线用户的流程就是没有红色部分的,其他用户就是整体的流程部分。

 

3、 为ChatLogsPlugin添加配置,在src/plugins/chatlogs目录下建立plugin.xml

com.hoo.openfire.chat.logs.ChatLogsPlugin
 
Chat Logs Plugin
User Chat Message Logs Plugins.
hoojo [http://hoojo.cnblogs.com]
 
1.0
28/03/2013
http://localhost:9090/openfire/plugins.jsp
3.7.1
gpl
 
 
description="Click to manage the service that allows users chat logs." />
 
 
 
 

如果你看过上一篇文章,这个配置你就不陌生了。最主要的还是class这个配置。在上面的配置中有一个adminconsole配置是页面的配置,暂且忽略。稍后再提,ok!

至此插件的核心部分已经配置完成了,如果你现在打包部署的话,肯定是可以保存到数据库。如果你想试试的话,可以按照上一篇文章的步骤进行打包部署。打包不带jsp的ant命令-java-plug-jar即可。这里我就不运行这步,继续完成其他的操作演示。

 

4、 在src/plugins/chatlogs目录中的com.hoo.openfire.chat.logs包下新建ChatLogsServlet,提供对外调用的接口,一般用它查询聊天记录和联系人信息

package com.hoo.openfire.chat.logs;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
 
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.codehaus.jackson.map.ObjectMapper;
import org.jivesoftware.admin.AuthCheckFilter;
import org.jivesoftware.util.ParamUtils;
 
import com.hoo.openfire.chat.logs.entity.ChatLogs;
 
/**
* function: 聊天记录插件对外接口
*
* @author hoojo
* @createDate 2012-9-18 下午09:32:21
* @file ChatLogsServlet.java
* @package com.hoo.openfire.chat.logs
* @project OpenfirePlugin
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class ChatLogsServlet extends HttpServlet {
 
private static final long serialVersionUID = 6981863134047161005L;
private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
private static final ObjectMapper mapper = new ObjectMapper();
private static DbChatLogsManager logsManager;
 
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
 
logsManager = DbChatLogsManager.getInstance();
 
// 取消权限验证,不登陆即可访问
AuthCheckFilter.addExclude("chatlogs");
AuthCheckFilter.addExclude("chatlogs/ChatLogsServlet");
}
 
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
 
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
 
ChatLogs entity = new ChatLogs();
String action = ParamUtils.getParameter(request, "action");
 
if ("last!contact".equals(action)) {
String sender = ParamUtils.getParameter(request, "sender");
entity.setSender(sender);
 
List
result = logsManager.findLastContact(entity);
request.setAttribute("lastContact", result);
request.getRequestDispatcher("/plugins/chatlogs/chatLogs-last-contact-service.jsp").forward(request, response);
 
} else if ("all!contact".equals(action)) {
List
result = logsManager.findAllContact();
request.setAttribute("allContact", result);
request.getRequestDispatcher("/plugins/chatlogs/chatLogs-all-contact-service.jsp").forward(request, response);
 
} else if ("remove!contact".equals(action)) {
Integer messageId = ParamUtils.getIntParameter(request, "messageId", -1);
logsManager.remove(messageId);
 
request.getRequestDispatcher("/plugins/chatlogs/chatLogs-service.jsp").forward(request, response);
 
} else if ("lately!contact".equals(action)) {
String sender = ParamUtils.getParameter(request, "sender");
entity.setSender(sender);
 
List
result = logsManager.findLastContact(entity);
StringWriter writer = new StringWriter();
mapper.writeValue(writer, result);
replyMessage(writer.toString(), response, out);
 
} else if ("entire!contact".equals(action)) {
List
result = logsManager.findAllContact();
StringWriter writer = new StringWriter();
mapper.writeValue(writer, result);
replyMessage(writer.toString(), response, out);
 
} else if ("delete!contact".equals(action)) {
Integer messageId = ParamUtils.getIntParameter(request, "messageId", -1);
 
StringWriter writer = new StringWriter();
mapper.writeValue(writer, logsManager.remove(messageId));
replyMessage(writer.toString(), response, out);
 
} else if ("query".equals(action)) {
 
String sender = ParamUtils.getParameter(request, "sender");
String receiver = ParamUtils.getParameter(request, "receiver");
String content = ParamUtils.getParameter(request, "content");
String createDate = ParamUtils.getParameter(request, "createDate");
 
try {
if (createDate != null && !"".equals(createDate)) {
entity.setCreateDate(new Timestamp(df.parse(createDate).getTime()));
}
} catch (Exception e) {
}
entity.setContent(content);
entity.setReceiver(receiver);
entity.setSender(sender);
 
List
logs = logsManager.query(entity);
 
StringWriter writer = new StringWriter();
mapper.writeValue(writer, logs);
replyMessage(writer.toString(), response, out);
} else {
String sender = ParamUtils.getParameter(request, "sender");
String receiver = ParamUtils.getParameter(request, "receiver");
String content = ParamUtils.getParameter(request, "content");
String createDate = ParamUtils.getParameter(request, "createDate");
 
try {
if (createDate != null && !"".equals(createDate)) {
entity.setCreateDate(new Timestamp(df.parse(createDate).getTime()));
}
} catch (Exception e) {
}
entity.setContent(content);
entity.setReceiver(receiver);
entity.setSender(sender);
 
List
> logs = logsManager.search(entity);
StringWriter writer = new StringWriter();
mapper.writeValue(writer, logs);
replyMessage(writer.toString(), response, out);
}
}
 
@Override
public void destroy() {
super.destroy();
 
// Release the excluded URL
AuthCheckFilter.removeExclude("chatlogs/ChatLogsServlet");
AuthCheckFilter.removeExclude("chatlogs");
}
 
private void replyMessage(String message, HttpServletResponse response, PrintWriter out) {
response.setContentType("text/json");
out.println(message);
out.flush();
}
}

这个类就是个普通的Servlet,做过JavaEE应该都比较了解了。更多关注的还是在servlet初始化的时候,将插件的配置目录忽略(即白名单)不通过URL资源权限验证,也就是用户不登陆也可以反问这个资源。

 

注意:这个类中使用到了jackson-all-1.6.2.jar这个包,你需要把这个jar包添加到当前项目的lib目录中,并且添加到构建路径中。添加到lib中后,在build.xml脚本运行的时候就不会编译错误了。

 

5、 写了Servlet当然少不了配置文件,在src/plugins/chatlogs根目录下新建一个web/WEB-INF目录,在web目录中新建一个web-custom.xml文件,内容如下

 
 
ChatLogsServlet
com.hoo.openfire.chat.logs.ChatLogsServlet
 
 
ChatLogsServlet
/ChatLogsServlet
 
 

这里我配置的是/ChatLogsServlet,但是我在后面调用的时候是无法调用到的。;但如果我用就可以调用到ChatLogsServlet接口。之前在上一篇文章我也提到了这个问题。

 

6、 接下来就是完成页面的编写,刚才在上面的plugin.xml文件中有一个adminconsole管理员控制台的配置。其中<item id="chatLogs-service" name="ChatLogs Service" url="chatLogs-service.jsp"这个配置是最重要的,在上一篇文章中一提到,这里再说下。Item元素的id对象页面中的<meta name="pageID" content="chatLogs-service"/>这里的content的内容;item的url指向页面的路径名称。

chatLogs-service.jsp显示所有聊天记录、查询聊天记录、删除聊天记录

<%@page import="com.hoo.openfire.chat.logs.entity.ChatLogs"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.text.DateFormat"%>
<%@page import="java.sql.Timestamp"%>
<%@page import="org.jivesoftware.util.ParamUtils"%>
<%@page import="org.jivesoftware.openfire.XMPPServer"%>
<%@page import="com.hoo.openfire.chat.logs.ChatLogsPlugin"%>
<%@page import="com.hoo.openfire.chat.logs.DbChatLogsManager"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 
 
 
ChatLogs 聊天记录 openfire plugin
 
 
<%
//ChatLogsPlugin plugin = (ChatLogsPlugin) XMPPServer.getInstance().getPluginManager().getPlugin("chatlogs");
String sender = ParamUtils.getParameter(request, "sender");
String receiver = ParamUtils.getParameter(request, "receiver");
String content = ParamUtils.getParameter(request, "content");
String createDate = ParamUtils.getParameter(request, "createDate");
 
ChatLogs entity = new ChatLogs();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
entity.setCreateDate(new Timestamp(df.parse(createDate).getTime()));
} catch (Exception e) {
}
entity.setContent(content);
entity.setReceiver(receiver);
entity.setSender(sender);
 
DbChatLogsManager logsManager = DbChatLogsManager.getInstance();
List
logs = logsManager.query(entity);
 
System.out.println(logsManager);
System.out.println(logs);
%>
 
 
所有聊天用户
查看
 
 
搜索
发送人:
接收人:
内容:
发送时间:
 
 
 
 
 
 
发送人
接收者
内容
发送时间
删除
 
 
 
<% for (int i = 0, len = logs.size(); i < len; i++) {
ChatLogs log = logs.get(i);
%>
">
<%=log.getSender() %>
<%=log.getReceiver() %>
<%=log.getContent() %>
<%=log.getCreateDate() %>
 
 
<% } %>
 
 
 
 
 

 

chatLogs-all-contact-service.jsp显示查询所有聊天联系人

<%@page import="org.xmpp.packet.JID"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 
 
 
ChatLogs 聊天记录 openfire plugin
 
 
 
ChatLogs 所有聊天联系人
 
 
 
联系人JID
他/她的聊天记录
【他/她】的联系人
 
 
 
<%
Object obj = request.getAttribute("allContact");
if (obj != null) {
List
allContact = (List
) obj;
for (int i = 0, len = allContact.size(); i < len; i++) {
String contact = allContact.get(i);
JID jid = new JID(contact);
%>
">
<%=contact %>
 
他/她的聊天记录
 
 
他/她的联系人
 
 
<% }
}
%>
 
 
 
 
 

 

chatLogs-last-contact-service.jsp查询某个用户的最近联系人

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 
 
 
ChatLogs 聊天记录 openfire plugin
 
 
 
ChatLogs 所有聊天联系人
 
 
 
联系人JID
【他/她】的联系人
他/她的聊天记录
 
 
 
<%
Object obj = request.getAttribute("lastContact");
if (obj != null) {
List
allContact = (List
) obj;
for (int i = 0, len = allContact.size(); i < len; i++) {
String contact = allContact.get(i);
%>
">
<%=contact %>
 
和他/她的聊天记录信息
 
 
和他/她的聊天记录信息
 
 
<% }
}
%>
 
 
 
 
 

OK,至此整个插件基本编写完成,下面就开始打包部署,打包是很关键的。

 

三、打包发布插件

1、 上次编写ant命令不能编译JSP页面有引用类的页面,这次重新提供代码。打可部署jar包。在工程的根目录中新建一个build目录,新建build.xml

 
 
 
 
 
 
 
 
 
 
 
 
uriroot="${plugin.path}/web"
outputDir="${webapp.path}/jsp-dist/src"
package="com.hoo.openfire.plugin.${plugin.name}" />
 
 
validateXml="false"
uriroot="${plugin.path}/web"
outputDir="${webapp.path}/jsp-dist/src"
package="com.hoo.openfire.plugin.${plugin.name}"
webXml="${plugin.web.xml}"/>
 
 
 
 
 
encoding="UTF-8" debug="on" failonerror="false"
srcdir="${webapp.path}/jsp-dist/src" excludes="**/*.smap">
-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

build.properties文件内容

tomcat.home=c:/SoftWare/tomcat-5.0.28/tomcat-5.0.28
webapp.path=D:/eclipse_workspace/OpenfirePlugin
 
plugin.name=chatLogs
plugin.path=D\:/eclipse_workspace/OpenfirePlugin/src/plugins/chatlogs

至于这里为什么需要这个配置,上一篇文章已经有讲明。如果你需要了解的话,请看上一篇博文。运行默认的build.xml脚本中的默认ant命令,就可以看到当前项目的根目录中有一个chatLogs.jar 这个就是我们编写好打好的插件包了。

 

2、 发布插件

在发布之前,我们还需要做一件事情。在ChatLogsServlet中我们有使用ObjectMapper这个json的工具包。我们打包可以成功,但是在ChatLogsServlet这个接口在调用的时候会出现问题。你需要把jackson-all-1.6.2.jar这个jar包放在你的openfire服务的lib目录,也就是C:\Program Files\openfire\lib这个目录中,这样整个环境中就可以使用这个jar包了。

 

小提示:如果你的插件发布成功,但是没有达到预期的效果。那么很有可能插件中的代码出现了异常信息。你可以进入管理员控制台的日志看到操作系统的日志信息。日志内容有常用的几个级别,经常看看日志对开发插件有帮助的。我拦截消息包的时候是分析消息包的xml内容作的判断,才完成这个插件的开发的。

 

发布插件:直接将插件放置在openfire服务器的plugins目录下。我的是在:C:\Program Files\openfire\plugins目录。重起openfire后你可以看到控制台输出我们插件中输出的内容,并且在C:\Program Files\openfire\plugins目录中可以看到该目录下多了一个chatlogs的目录(openfire可以自动解压jar包)。

当你在关闭服务器的瞬间,也会打印销毁插件的消息。

 

插件按照成功后,访问页面你就可以看到安装好的插件了。

至此,整个插件部署成功了。

 

3、 测试插件

我们开一个spark和一个WebIM聊天程序进行互相聊天。内容大概如下:

发送聊天内容的时候你可以看到启动的openfire控制台有一些我们打印的报文。当聊天终止后,我们可以关闭openfire服务器。然后启动HSQL数据库查看下ofChatLogs这张表的数据,如果数据保存成功。那么效果达到了,如果没有消息内容,你得看看是哪里错误或遗漏了。建议你看看的日志,可能会有提示信息。我这里查询后,大致内容如下:

OK,下面我们可以看看在 openfire管理员控制台服务器设置左侧菜单中的ChatLogs Servcie 这个就是我们的插件。点击后就可以看到上面的测试的聊天内容了,你可以输入发送者、接受者等内容进行搜索,还可以点击“所有聊天用户”查看连接,查询所有聊天用户以及他们的聊天记录信息。

 

随后,我们应该测试下我们编写的ChatLogsServlet对外的查询接口。在浏览器中直接请求:会返回一段JSON数据,存放所有的聊天用户的sessionJID。

["boy@127.0.0.1/WebIM","girl@127.0.0.1/WebIM",]

 

请求:

[]

 

请求:

返回聊天记录所有结果,JSON格式的数组集合

请求:

查询hoojo和boy的聊天内容,JSON格式的数组集合

 

其他的还可以通过内容,发送日期进行搜索等等,基本功能就这样的。如果你想要用到自己的系统中,如果涉及到跨域,你需要用到Proxy、URLConnection、HttpClient等网络编程的方法来解决跨域问题。

本文转自hoojo博客园博客,原文链接:http://www.cnblogs.com/hoojo/archive/2013/03/29/openfire_plugin_chatlogs_plugin_.html,如需转载请自行联系原作者
你可能感兴趣的文章
mysql中Table is read only错误解决方法
查看>>
博客园是不是应该取消反对按钮或者改进反对按钮
查看>>
Cocos2d-X中实现批处理精灵
查看>>
mybatis源码追踪2——将结果集映射为map
查看>>
微信公众平台门店管理
查看>>
整理分享C#通过user32.dll模拟物理按键操作的代码
查看>>
js日期控件
查看>>
uCGUI窗口重绘代码分析
查看>>
点滴的积累---J2SE学习小结
查看>>
Sql Server系列:数据库对象
查看>>
C#中string.format的格式和用法
查看>>
获取指定日期的常用前后节点(月初月末周一周末等等)
查看>>
Android系统Surface机制的SurfaceFlinger服务渲染应用程序UI的过程分析
查看>>
现实中如何评判路遥《人生》中的高加林?
查看>>
[翻译svg教程]svg学习系列 开篇
查看>>
Apache Solr采用Java开发、基于Lucene的全文搜索服务器
查看>>
Pro * c Oracle 12c
查看>>
Oracle Hints具体解释
查看>>
DB9 公头母头引脚定义及连接
查看>>
我们应当如何做需求分析
查看>>